package lpcn.xbee;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;

import javax.swing.JButton;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import com.rapplogic.xbee.api.ApiId;
import com.rapplogic.xbee.api.PacketListener;
import com.rapplogic.xbee.api.XBeeAddress64;
import com.rapplogic.xbee.api.XBeeResponse;
import com.rapplogic.xbee.api.zigbee.ZNetRxResponse;
import com.rapplogic.xbee.api.zigbee.ZNetTxStatusResponse;
import com.rapplogic.xbee.util.ByteUtils;

public class SmartPowerAP
{
	public final static Logger log = Logger.getLogger(SmartPowerAP.class);

	/**
	 * @param args
	 */
	public static void main(String[] arguments)
	{
		PropertyConfigurator.configure("log4j.properties");
		APGUI bf = new APGUI();
	}
}

class APGUI extends GeneralGUI implements ActionListener
{
	// CLASS VARIABLES
	ServerSocket serverSocket;

	// THREADS
	AddFilesToQueue tAddFilesToQueue = new AddFilesToQueue();
	WiFiConnectionListener tWiFiConnectionListener = new WiFiConnectionListener();
	SendWiFiInfo tSendWiFiInfo = new SendWiFiInfo();

	// GUI VARIABLES
	JButton runAddFileScriptButton = new JButton("Run Add Files Script");

	// Constructor
	public APGUI()
	{
		setTitle("AP in the Hizzouce");

		runAddFileScriptButton.addActionListener(this);

		pane.add(runAddFileScriptButton);

		add(pane);
		setVisible(true);

		try
		{
			serverSocket = new ServerSocket(port);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

		packetListener = new PacketListener()
		{
			public void processResponse(XBeeResponse response)
			{
				//System.out.println("Received packet: " + response);
				if (response.getApiId() == ApiId.ZNET_RX_RESPONSE)
				{
					int[] payload;          // Stores the payload of the received packet
					ZNetRxResponse ZNetResponse = new ZNetRxResponse();             // Stores the ZNetRxResonse type of the received packet

					ZNetResponse = (ZNetRxResponse) response;       // Cast received packet to the correct type (ZNetRxResonse)
					payload = ZNetResponse.getData();                       // Store the data from the packet into the payload array

					switch(payload[0])      // Look at the status byte (first byte) of the payload
					{
					case '0':       // WIFI_REQUEST : Requests a Wi-Fi access point to connect to
						System.out.println("Wi-Fi request received");
						tWiFiConnectionListener.start();
						tSendWiFiInfo.start();
						break;

					case '1':       // WIFI_INFO : Contains Wi-Fi access point information
						// not needed on the access point
						break;

					case '2':       // WIFI_STOP : Informs Wi-Fi AP that the connection is closing
						try
						{
							//clientObjectOutputStream.close();
							connectedWiFi = false;
							tWiFiDataListener.stop();
							clientSocket.close();
						}
						catch (IOException e)
						{
							e.printStackTrace();
						}
						break;

					case '3':       // FILE_TRANSFER_REQUEST : Contains file information
						String fileInfoString = removeFirstChar(ByteUtils.toString(payload));   // Strip the status (first) byte from the payload
						String[] fileInfo = fileInfoString.split(",");          // Split the data into separate strings for file name and size
						String fileName = fileInfo[0];                                          // Store the file name
						long fileSize = Long.parseLong(fileInfo[1]);            // Convert the file size string into a long and store it
						//System.out.println("File Transfer Request received: " + fileName + " of size " + fileSize + " bytes");
						queueFiles.add(new FileInfo(fileName, fileSize, false));        // Add the file to the write queue
						queueBytes = queueBytes + fileSize;
						//receiveFileTransferRequest(fileName, fileSize);               // Handle the file transfer request
						break;

					case '4':       // FILE_DATA : Contains 70 bytes of file data 
						int[] dataInt = removeFirstArrayElement(payload);       // Strip the status (first) byte from the payload
						queueDataReceived.add(dataInt);         // Add the byte array to the received data queue
						break;

					case '5':       // INCOMING_FRIEND_TO_RECEIVE : Contains file information
						friendReadyToReceive = true;
						//System.out.println("received a ready to receive packet from friend");
						break;

					default:
						//System.out.println("Received random ass packet: " + response);
						//System.out.println("Packet length is this shit: " + ZNetResponse.getLength());
						//System.out.println("Payload length is fuckin: " + ZNetResponse.getData().length);
						break;
					}
				}
			}
		};
	}

	// Event handler
	public void actionPerformed(ActionEvent event)
	{
		Object source = event.getSource();
		if(source == startButton)
		{
			openXBeeInterface(devicePort.getText(), 9600);
			xbee.setDestinationAddress64(new XBeeAddress64(0, 0x13, 0xa2, 0, 0x40, 0x30, 0xc1, 0x3e));
			while(!xbee.xbee.isConnected())
			{
				// Do nothing until the xbee has been connected to
			}
			xbee.xbee.addPacketListener(packetListener);
		}
		else if(source == sendPacketButton)
		{
			sendWiFiInfo();

			//int[] payload = new int[] { '6' };

		}
		else if(source == sendFileButton)
		{
			File fileToSend = new File(fileLocation.getText());             // Look up the file on the hard drive
			FileInfo fileInfo = new FileInfo(fileToSend.getName(), fileToSend.length(), true);      // Create a FileInfo object
			sendFileTransferRequest(fileInfo);              // Send a file transfer request
		}
		else if(source == runAddFileScriptButton)
		{
			scriptStartTime = System.currentTimeMillis();
			tAddFilesToQueue.start();
		}
	}

	public void sendWiFiInfo()
	{
		int[] payload = new int[] { '1', 'u', 'l', 'w', 'i', 'r', 'e', 'l', 'e', 's', 's', ',', 'M', 'a', 'n', 'a', 'g', 'e', 'd', ',', 'A', 'n', 'y' };
		System.out.println("Sending packet: " + xbee.XBeeSendPacket(payload));
	}

	// THREADS
	// Waits for a connection on the socket, and then sets the WiFi connection status to true 
	class WiFiConnectionListener implements Runnable
	{
		private volatile Thread threadWiFiConnectionListener;

		void start()
		{
			threadWiFiConnectionListener = new Thread(this);
			threadWiFiConnectionListener.start();
		}

		public void run()
		{
			try
			{
				clientSocket = serverSocket.accept();   // Wait for the client to connect on the socket
				connectedWiFi = true;                                   // Let the program know WiFi is connected
				clientObjectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream());
				clientObjectInputStream = new ObjectInputStream(clientSocket.getInputStream());
				tWiFiDataListener.start();                              // Start the WiFi data listener
				threadWiFiConnectionListener = null;    // Kill this thread?
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}

	class SendWiFiInfo implements Runnable
	{
		private volatile Thread threadSendWiFiInfo;

		public void stop()
		{
			threadSendWiFiInfo = null;
		}

		public void start()
		{
			threadSendWiFiInfo = new Thread(this);
			threadSendWiFiInfo.start();
		}

		public void run()
		{
			int[] payload = new int[] { '1', 'u', 'l', 'w', 'i', 'r', 'e', 'l', 'e', 's', 's', ',', 'M', 'a', 'n', 'a', 'g', 'e', 'd', ',', 'A', 'n', 'y' };
			System.out.println("sending connection info packet");
			while(xbee.XBeeSendPacket(payload) != ZNetTxStatusResponse.DeliveryStatus.SUCCESS);
			//System.out.println("Sending packet: " + xbee.XBeeSendPacket(payload));
		}
	}

	class AddFilesToQueue implements Runnable
	{
		private volatile Thread threadAddFilesToQueue;

		long ass;
		long file1;
		long file2;
		long file3;
		long file4;
		long file5;
		long file6;
		long file7;
		long file8;
		long file9;

		public void stop()
		{
			threadAddFilesToQueue = null;
		}

		public void start()
		{
			File asstemp = new File(FILEPATH + "ass.jpg");

			File file1temp = new File(FILEPATH + "ap1");
			File file2temp = new File(FILEPATH + "ap2");
			File file3temp = new File(FILEPATH + "ap3");

			/*
                        File file1temp = new File(FILEPATH + "file1");
                        File file2temp = new File(FILEPATH + "file2");
                        File file3temp = new File(FILEPATH + "file3");
			 */
			File file4temp = new File(FILEPATH + "file4");
			File file5temp = new File(FILEPATH + "file5");
			File file6temp = new File(FILEPATH + "file6");
			File file7temp = new File(FILEPATH + "file7");
			File file8temp = new File(FILEPATH + "file8");
			File file9temp = new File(FILEPATH + "file9");

			ass = asstemp.length();
			file1 = file1temp.length();
			file2 = file2temp.length();
			file3 = file3temp.length();
			file4 = file4temp.length();
			file5 = file5temp.length();
			file6 = file6temp.length();
			file7 = file7temp.length();
			file8 = file8temp.length();
			file9 = file9temp.length();

			threadAddFilesToQueue = new Thread(this);
			threadAddFilesToQueue.start();
		}

		public void run()
		{
			try
			{
				System.out.println("Starting add file thread");

				Thread.sleep(5000);
				sendFileTransferRequest(new FileInfo("ap1", file1, true));
				sendFileTransferRequest(new FileInfo("ap2", file2, true));
				sendFileTransferRequest(new FileInfo("ap3", file3, true));
				Thread.sleep(4000);
				sendFileTransferRequest(new FileInfo("ap3", file3, true));
				sendFileTransferRequest(new FileInfo("ap3", file3, true));
				sendFileTransferRequest(new FileInfo("ap3", file3, true));
				sendFileTransferRequest(new FileInfo("ap3", file3, true));
				sendFileTransferRequest(new FileInfo("ap3", file3, true));
			}
			catch (InterruptedException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}